#pragma once

#include <Eigen/Dense>
#include "eigen/hidden_layer.h"

namespace  ldl_eigen
{
class Conv : public HiddenLayer
{
public:
    using HiddenLayer::forward;
    using HiddenLayer::backward;
    Conv(int64_t img_width, int64_t img_height, int64_t kernel_size, int64_t stride = 1, int64_t padding = 0);
    virtual ~Conv() = default;

    virtual void forward() override;

    virtual void backward() override;

    virtual void update() override;

    void set_kernel(const Eigen::MatrixXf &kernel);
    Eigen::MatrixXf& kernel_gradient();
    void set_bias(float bias);
    float bias_gradient();

    static void conv(const Eigen::Ref<Eigen::MatrixXf> &input, const Eigen::Ref<Eigen::MatrixXf> &kernel, float bias, int64_t stride, Eigen::Ref<Eigen::MatrixXf> output);
private:
    /**
     * @brief 图像宽度
     */
    int64_t m_img_width;

    /**
     * @brief 图像高度
     */
    int64_t m_img_height;

    /**
     * @brief 添加padding后的图像宽度
     */
    int64_t m_padding_img_width;

    /**
     * @brief 添加padding后的图像高度
     */
    int64_t m_padding_img_height;

    /**
     * @brief 卷积核
     */
    Eigen::MatrixXf m_kernel{};

    /**
     * @brief 损失对卷积核的偏导数
     */
    Eigen::MatrixXf m_kernel_gradient{};

    /**
     * @brief 偏置
     */
    float m_bias;

    /**
     * @brief 损失对偏置的偏导数
     */
    float m_bias_gradient;

    /**
     * @brief 步进
     */
    int64_t m_stride;

    /**
     * @brief 行滑动的最大值​
     */
    int64_t m_row_sliding_max;

    /**
     * @brief 列滑动的最大值
     */
    int64_t m_col_sliding_max;

    /**
     * @brief 单张图片输出的高度
     */
    int64_t m_output_height;

    /**
     * @brief 单张图片输出的宽度
     */
    int64_t m_output_width;

    /**
     * @brief 填充
     */
    int64_t m_padding;
};
}
